package com.sgl.myview.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

import com.sgl.myview.R;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by sunqiyong on 2016/12/5.
 */
public class MyGridView extends View {
    private int mRow;//行
    private int mCol;//列
    private int mLineColor;//线的颜色
    private int mLineWidth;//线的宽度
    private int mTitleColor;//字段的颜色
    private int mTitleSize;//字段的字体大小
    private int mContentColor;//内容的颜色
    private int mContentSize;//内容的字体大小
    private int mFirstColWidth;//第一列（标题字段）的宽
    private int mPadding = 10;

    private float mColWidth;//内容列的宽度
    int mHeight = 0;

    private Paint mPaint;//画笔

    //表格的内容
    private List<List<String>> mContents = new ArrayList<>();

    public MyGridView(Context context) {
        this(context, null);
    }

    public MyGridView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyGridView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //初始化我们自定义的属性
        initMyData(context, attrs, defStyleAttr);
        //createData();//该步骤测试用
        mPaint = new Paint();
    }

    /**
     * 获取自定义属性
     */
    private void initMyData(Context context, AttributeSet attrs, int defStyleAttr) {
        TypedArray mTypeArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyGridView, defStyleAttr, 0);
        for (int i = 0; i < mTypeArray.getIndexCount(); i++) {
            int attr = mTypeArray.getIndex(i);
            switch (attr) {
                case R.styleable.MyGridView_myRow:
                    mRow = mTypeArray.getInteger(attr, 1);
                    break;
                case R.styleable.MyGridView_myCol:
                    mCol = mTypeArray.getInteger(attr, 1);
                    break;
                case R.styleable.MyGridView_lineColor:
                    mLineColor = mTypeArray.getColor(attr, Color.BLACK);
                    break;
                case R.styleable.MyGridView_lineWidth:
                    mLineWidth = mTypeArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 2, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.MyGridView_myTitleColor:
                    mTitleColor = mTypeArray.getColor(attr, Color.BLACK);
                    break;
                case R.styleable.MyGridView_myTitleSize:
                    mTitleSize = mTypeArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.MyGridView_myContentColor:
                    mContentColor = mTypeArray.getColor(attr, Color.BLACK);
                    break;
                case R.styleable.MyGridView_myContentSize:
                    mContentSize = mTypeArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.MyGridView_myFirstColWidth:
                    mFirstColWidth = mTypeArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 50, getResources().getDisplayMetrics()));
                    break;
                case R.styleable.MyGridView_myPadding:
                    mPadding = mTypeArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 15, getResources().getDisplayMetrics()));
                    break;
            }
        }
        mTypeArray.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
        //如果数据集为空，那么直接返回
        if (mContents == null || mContents.size() == 0) {
            return;
        }
        /***
         * 设置高度
         */
        int specWidthSize = MeasureSpec.getSize(widthMeasureSpec);
        int specHeightMode = MeasureSpec.getMode(heightMeasureSpec);
        int specHeightSize = MeasureSpec.getSize(heightMeasureSpec);
        //初始化一下高度
        mHeight = 0;
        // 如果高度度是一个固定的值,或者是match_parent，那么久用它自己测出来的高度值
        if (specHeightMode == MeasureSpec.EXACTLY) {
            mHeight = specHeightSize;
        } else {
            //用来让我们的文本实现换行
            StaticLayout mStaticLayout;
            TextPaint mTextPaint = new TextPaint();
            if (mCol != 1) {//如果 列数 不为 1
                mColWidth = (specWidthSize - mFirstColWidth - mLineWidth * (mCol + 1)) / (mCol - 1);
            } else {//如果只有 1 列，那么首列宽度为view自己测量的值
                mFirstColWidth = specWidthSize;
            }
            for (int i = 0; i < mRow; i++) {
                //currentRowHeight 用来记录每一行中，所有列中文本段落高度的最高值
                int currentRowHeight = mLineWidth;
                for (int j = 0; j < mCol; j++) {
                    if (j == 0) {//当为第一列的时候
                        mTextPaint.setTextSize(mTitleSize);//设置字体大小
                        String content = "";
                        try {
                            content = mContents.get(i).get(j);
                        } catch (Exception ignored) {
                            /**
                             * 这么做主要是为了防止mContents.get(i).get(j)报空指针异常或者越界异常
                             * 因为我们有时候在布局文件中设置了行和列，但是传进来的数据却没那么多
                             * 比如我设置的是20行20列，但是我传进来的数据只有5行5列，那么当捕获相关异常后
                             * 不做处理，就当空String用
                             */
                        }
                        /**
                         * new 一个 StaticLayout 对象，根据 StaticLayout 对象，拿到这个文本段落的高度
                         * 说一下这个参数
                         * 参数1：文本内容
                         * 参数2：文本的渲染格式（字体大小、颜色等等）
                         * 参数3：文本的宽度（当文本长度大于该宽度后，就会换行）
                         * 参数4：文本的对其方式（ALIGN_CENTER， ALIGN_NORMAL， ALIGN_OPPOSITE ）
                         * 参数5：行间距
                         * 参数6：在基础行间距上再添加多少
                         * 参数7：不清楚
                         */
                        mStaticLayout = new StaticLayout(content, mTextPaint, mFirstColWidth - mPadding * 2, Layout.Alignment.ALIGN_CENTER, 1.0F, 0.0F, true);
                        //如果这个文本段落的高度大于当前行记录的高度，那么替换值，保证 currentRowHeight 代表当前行的最高高度
                        if (mStaticLayout.getHeight() > currentRowHeight) {
                            currentRowHeight = mStaticLayout.getHeight();
                        }
                    } else if (i == 0) {//若是第一行的数据
                        mTextPaint.setTextSize(mTitleSize);
                        String content = "";
                        try {
                            content = mContents.get(i).get(j);
                        } catch (Exception ignored) {
                        }
                        mStaticLayout = new StaticLayout(content, mTextPaint, (int) (mColWidth - mPadding * 2), Layout.Alignment.ALIGN_CENTER, 1.0F, 0.0F, true);
                        if (mStaticLayout.getHeight() > currentRowHeight) {
                            currentRowHeight = mStaticLayout.getHeight();
                        }
                    } else {//表示为内容区域的内容（非标题段）
                        mTextPaint.setTextSize(mContentSize);
                        String content = "";
                        try {
                            content = mContents.get(i).get(j);
                        } catch (Exception ignored) {
                        }
                        mStaticLayout = new StaticLayout(content, mTextPaint, (int) (mColWidth - mPadding * 2), Layout.Alignment.ALIGN_CENTER, 1.0F, 0.0F, true);
                        if (mStaticLayout.getHeight() > currentRowHeight) {
                            currentRowHeight = mStaticLayout.getHeight();
                        }
                    }
                }
                //把当前行的最大值 加到 mHeight（总高度）上
                mHeight += currentRowHeight;
            }
            /**
             *  所有循环结束 控件总高度
             * mRow * 2 * mPadding     每一行里面有2个padding
             * (mRow + 1) * mLineWidth    （行数加1）条线条宽度
             * mLineWidth / 2           第一行线条由于宽度是2倍的 mLineWidth，多加了一条宽度
             * mHeight      刚刚测量的文本总高度
             */
            mHeight = mRow * 2 * mPadding + (mRow + 1) * mLineWidth + mLineWidth / 2 + mHeight;
        }
        setMeasuredDimension(specWidthSize, mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //如果数据集为空，那么直接返回
        if (mContents == null || mContents.size() == 0) {
            return;
        }
        //获取控件的宽度
        int width = getMeasuredWidth();
        mPaint.setStrokeWidth(mLineWidth);//设置线条宽度
        mPaint.setColor(mLineColor);//设置线条颜色


        float mTotalHeight = mLineWidth;

        TextPaint mTextPaint = new TextPaint();
        mTextPaint.setAntiAlias(true);// 消除锯齿
        StaticLayout mStaticLayout;//参考上

        for (int i = 0; i < mRow; i++) {
            int currentRowHeight = 0;
            for (int j = 0; j < mCol; j++) {

                if (j == 0) {
                    mTextPaint.setColor(mTitleColor);
                    mTextPaint.setTextSize(mTitleSize);
                    String content = "";
                    try {
                        content = mContents.get(i).get(j);
                    } catch (Exception ignored) {
                        /**
                         * 这么做主要是为了防止mContents.get(i).get(j)报空指针异常或者越界异常
                         * 因为我们有时候在布局文件中设置了行和列，但是传进来的数据却没那么多
                         * 比如我设置的是20行20列，但是我传进来的数据只有5行5列，那么当捕获相关异常后
                         * 不做处理，就当空String用
                         */
                    }
                    mStaticLayout = new StaticLayout(content, mTextPaint, mFirstColWidth - mPadding * 2, Layout.Alignment.ALIGN_CENTER, 1.0F, 0.0F, true);
                    canvas.save();//保存下画布的状态
                    /**
                     * 设置绘制文本的位置
                     * 参数 1 ：横坐标
                     * 参数 2 ：纵坐标
                     */
                    canvas.translate(mPadding + mLineWidth * (j + 2), mTotalHeight + mPadding);
                    mStaticLayout.draw(canvas);
                    canvas.restore();//取出刚刚保存的画布的状态
                    if (mStaticLayout.getHeight() > currentRowHeight) {
                        currentRowHeight = mStaticLayout.getHeight();
                    }
                } else if (i == 0) {
                    mTextPaint.setColor(mTitleColor);
                    mTextPaint.setTextSize(mTitleSize);
                    String content = "";
                    try {
                        content = mContents.get(i).get(j);
                    } catch (Exception ignored) {
                    }
                    mStaticLayout = new StaticLayout(content, mTextPaint, (int) (mColWidth - mPadding * 2), Layout.Alignment.ALIGN_CENTER, 1.0F, 0.0F, true);
                    canvas.save();
                    canvas.translate(mFirstColWidth + mLineWidth * (j + 3) + mColWidth * (j - 1) + mPadding, mTotalHeight + mPadding);
                    mStaticLayout.draw(canvas);
                    canvas.restore();
                    if (mStaticLayout.getHeight() > currentRowHeight) {
                        currentRowHeight = mStaticLayout.getHeight();
                    }
                } else {
                    mTextPaint.setColor(mContentColor);
                    mTextPaint.setTextSize(mContentSize);
                    String content = "";
                    try {
                        content = mContents.get(i).get(j);
                    } catch (Exception ignored) {
                    }
                    mStaticLayout = new StaticLayout(content, mTextPaint, (int) (mColWidth - mPadding * 2), Layout.Alignment.ALIGN_CENTER, 1.0F, 0.0F, true);
                    canvas.save();
                    canvas.translate(mFirstColWidth + mLineWidth * (j + 3) + mColWidth * (j - 1) + mPadding, mTotalHeight + mPadding);
                    mStaticLayout.draw(canvas);
                    canvas.restore();
                    if (mStaticLayout.getHeight() > currentRowHeight) {
                        currentRowHeight = mStaticLayout.getHeight();
                    }
                }
            }
            //总高度 = 当前记录的总行高 + 当前行的行高 + 行下面的padding距离
            mTotalHeight = currentRowHeight + mTotalHeight + mPadding;
            if (i != mRow - 1) {//最后一行我们会作特殊处理
                //画横向的线条
                canvas.drawLine(0, mTotalHeight + mPadding, width, mTotalHeight + mPadding, mPaint);
            }
            //总高度 = 刚刚画的线条高度 + 当前记录的总行高 + 行上面的padding距离
            mTotalHeight = mLineWidth + mTotalHeight + mPadding;
        }

        //下面开始画四周的边框和中间竖直的线条
        /**
         * 由于画最外面一层的线条，一半画出来了，还有一半在外面显示不出来，所以这里用2倍的线条画
         */
        mPaint.setStrokeWidth(mLineWidth * 2);
        canvas.drawLine(0, 0, 0, mTotalHeight, mPaint);//最左边的线条
        canvas.drawLine(0, 0, width, 0, mPaint);//最上面的线条
        canvas.drawLine(width, 0, width, mTotalHeight, mPaint);//最右面的线条
        mPaint.setStrokeWidth(mLineWidth);//最下面的线条不用加框处理
        canvas.drawLine(0, mTotalHeight, width, mTotalHeight, mPaint);
        for (int col = 1; col < mCol; col++) {
            if (col == 1) {//画内部竖直方向的第一条线条（从左往右）
                canvas.drawLine(mFirstColWidth + mLineWidth * (col + 2), 0, mFirstColWidth + mLineWidth * (col + 2), mTotalHeight, mPaint);
            } else {//画内部竖直方向的非第一条线条
                canvas.drawLine(mFirstColWidth + mColWidth * (col - 1) + mLineWidth * (col + 2), 0, mFirstColWidth + mColWidth * (col - 1) + mLineWidth * (col + 2), mTotalHeight, mPaint);
            }
        }

    }

    public void setContent(List<List<String>> mContents) {
        this.mContents.clear();
        this.mContents.addAll(mContents);
        postInvalidate();
    }
}
